﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Security.Cryptography;

namespace bleCore
{
    public class BleMsgReceiver
    {
        GattCharacteristic gatt;
        MyBleDevice device;
        bool running = false;
        public DataReceivedEvent DataRecieved;
        static Hashtable gatt_table = Hashtable.Synchronized(new Hashtable());
        public static BleMsgReceiver GetReceiver(MyBleDevice device, string gatt_flag)
        {
            string key = String.Format("{0}#{1}#{2}", device.GetHashCode().ToString(), device.DEVICE_ID, gatt_flag);
            if (gatt_table.ContainsKey(key)) return gatt_table[key] as BleMsgReceiver;
            BleMsgReceiver result = new BleMsgReceiver();
            result.device = device;
            var gatt = device.UseCharacteristic.FirstOrDefault(r => r.Uuid.Equals(new Guid(gatt_flag)));
            if (gatt == null)
                throw new BleGattNotFoundException(String.Format("在设备{0}下无法找到GATT={1}的服务",device.DEVICE_ID,gatt_flag));
            result.gatt = gatt;
            result.gatt.ProtectionLevel = GattProtectionLevel.Plain;
            result.gatt.ValueChanged += result.Gatt_ValueChanged;
            device.ConnectLost += result.connect_lost;
            gatt_table.Add(key, result);
            return result;
        }

        private void connect_lost(MyBleDevice d)
        {
            running = false;
            string key_prefix = String.Format("{0}#{1}#", d.GetHashCode().ToString(), d.DEVICE_ID);
            List<string> keys = new List<string>();
            foreach (DictionaryEntry dic in gatt_table)
            {
                string key = dic.Key.ToString();
                if (key.StartsWith(key_prefix))
                    keys.Add(key);
            }
            foreach (var key in keys)
            {
                gatt_table.Remove(key);
            }
        }

        private void Gatt_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
            if (DataRecieved == null) return;
            if (!running) return;
            byte[] data;
            CryptographicBuffer.CopyToByteArray(args.CharacteristicValue, out data);
            foreach (var handle in DataRecieved.GetInvocationList())
            {
                ((DataReceivedEvent)handle).Invoke(device, sender, data);
            }
        }

        public void Stop() 
        {
            running = false;
        }
        public async void Connect()
        {
            GattClientCharacteristicConfigurationDescriptorValue t = GattClientCharacteristicConfigurationDescriptorValue.None; ;
            if ((gatt.CharacteristicProperties & GattCharacteristicProperties.Notify) == GattCharacteristicProperties.Notify)
                t = GattClientCharacteristicConfigurationDescriptorValue.Notify;
            else if ((gatt.CharacteristicProperties & GattCharacteristicProperties.Indicate) == GattCharacteristicProperties.Indicate)
                t = GattClientCharacteristicConfigurationDescriptorValue.Indicate;
            var writer = await gatt.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(t);
            if (writer.Status == GattCommunicationStatus.Unreachable) {
                Connect();
            }
            running = true;
        }
    }
}
